#pragma once

#include <iostream>
#include <cstring>
#include <memory>
#include <unordered_map>

#include "Connection.hpp"
#include "Epoller.hpp"

#define EPOLL_BLOCK -1 // 设置阻塞时间

static const int maxevents = 64;

class TcpServer
{

    Epoll::Epoller _epoller;
    std::unordered_map<int, Connection *> _connections;
    struct epoll_event _revs[maxevents];
    int _timeout;
    bool _isrunning;

public:
    TcpServer() : _isrunning(false), _timeout(EPOLL_BLOCK)
    {
        // 初始化 epoller 对象
        _epoller.InitEoller();
    }

    ~TcpServer()
    {
    }
    
    void RemoveConntion(int sockfd)
    {
        if(!IsConnectionExists(sockfd))
        {
            return;
        }

        // 1. 清理自己关心的事件
        _connections[sockfd]->SetEvents(0);

        // 2. 清理epoller 中对于sockfd 的关心
        _epoller.DelEvent(sockfd);

        // 3.移除 _conntion
        _connections.erase(sockfd);
    }

    // 查询连接是否存在
    bool IsConnectionExists(int sockfd)
    {
        return _connections.count(sockfd) ? true : false;
    }

    void AddConnection(Connection *conn)
    {
        if (conn == nullptr || IsConnectionExists(conn->Sockfd()))
            return;

        // 1. 将连接加入哈希表
        _connections.insert(std::make_pair(conn->Sockfd(), conn));
        lg.LogMessage(Info, "Add a new connection success,sockfd :%d\n", conn->Sockfd());

        // 2. 让epoller 管理
        _epoller.AddEvent(conn->Sockfd(), conn->Events());
    }

    void LoopOnce(int timeout)
    {
        int n = _epoller.Wait(_revs, maxevents, timeout);
        // sleep(5);

        for (int i = 0; i < n; i++)
        {
            int sockfd = _revs[i].data.fd;
            uint32_t event = _revs[i].events;

            // 将文件描述符的出错处理,一律改为读写出错处理
            if ((event & EPOLLERR) || (event & EPOLLHUP))
            {
                event |= (EPOLLIN | EPOLLOUT);
            }

            // 文件描述符有新信息到来,且文件文件描述符合法
            if ((event & EPOLLIN) && IsConnectionExists(sockfd))
            {
                Connection *tmp = _connections[sockfd];
                if (tmp->_recver)
                {
                    tmp->_recver(tmp);
                }
            }

            if ((event & EPOLLOUT) && IsConnectionExists(sockfd))
            {
                Connection *tmp = _connections[sockfd];
                if (tmp->_sender)
                {
                    tmp->_sender(tmp);
                }
            }
        }
    }

    // 事件派发器
    void Dispatcher()
    {
        _isrunning = true;
        while (_isrunning)
        {
            LoopOnce(_timeout);
        }
        _isrunning = false;
    }

    void EnableReadWrite(int sockfd, bool readable, bool writeable)
    {
        if (!IsConnectionExists(sockfd))
        {
            return;
        }

        //! 采用 ET模式
        uint32_t events = ((readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0)|EPOLLET);

        //1.  设置 connection 对指定事件的关心
        _connections[sockfd]->SetEvents(events);

        //2. 修改
        _epoller.ModEvent(sockfd,_connections[sockfd]->Events());
    }

    void InitServer()
    {
    }
};